//////////////////////////////////////////////
// File				:	Mouse.cpp
//
// Author			:	Nick Faletra (NF)
//
// Date Created		:	12/22/2013
//////////////////////////////////////////////
#include "Mouse.h"

CMouse::CMouse(IDirectInput8* pDI, HWND hWnd, bool bExclusive)
{
	if (FAILED(pDI->CreateDevice(GUID_SysMouse, &m_pDevice, NULL)))
		DIERRBOX(hWnd, "Failed to create Mouse device.");

	if (FAILED(m_pDevice->SetDataFormat(&c_dfDIMouse2)))
		DIERRBOX(hWnd, "Failed to set data format on Mouse.");

	DWORD dwFlags = DISCL_FOREGROUND;
	dwFlags |= bExclusive ? DISCL_EXCLUSIVE : DISCL_NONEXCLUSIVE;

	if (FAILED(m_pDevice->SetCooperativeLevel(hWnd, dwFlags)))
		DIERRBOX(hWnd, "Failed to set cooperative level on Mouse.");

	DIPROPDWORD dipdw;
	memset(&dipdw, 0, sizeof(DIPROPDWORD));

	dipdw.diph.dwSize		= sizeof(DIPROPDWORD);
	dipdw.diph.dwHeaderSize	= sizeof(DIPROPHEADER);
	dipdw.diph.dwObj		= 0;
	dipdw.diph.dwHow		= DIPH_DEVICE;
	dipdw.dwData			= BUFFER_SIZE;

	if (FAILED(m_pDevice->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)))
		DIERRBOX(hWnd, "Could not Set the Properties for Buffered Input for Mouse.");

	if (FAILED(m_pDevice->Acquire()))
		DIERRBOX(hWnd, "Failed to acquire Mouse.");

	DIDEVCAPS didCaps;
	memset(&didCaps, 0, sizeof(DIDEVCAPS));
	didCaps.dwSize = sizeof(didCaps);

	m_pDevice->GetCapabilities(&didCaps);
	m_nNumButtons = didCaps.dwButtons;

	memset(&m_diMouseState, 0, sizeof(DIMOUSESTATE2));
	memset(&m_diPrevMouseState, 0, sizeof(DIMOUSESTATE2));

	SetPosX(0);
	SetPosY(0);
}

bool CMouse::ReadDevice()
{
	if (m_pDevice)
		return false;

	memcpy(&m_diPrevMouseState, &m_diMouseState, sizeof(m_diPrevMouseState));

	if (FAILED(m_pDevice->GetDeviceState(sizeof(m_diMouseState), (void*)&m_diMouseState)))
	{
		if (FAILED(m_pDevice->Acquire()))
			return false;

		if (FAILED(m_pDevice->GetDeviceState(sizeof(m_diMouseState), (void*)&m_diMouseState)))
			return false;
	}

	SetPosX(GetPosX() + MovementX());
	SetPosY(GetPosY() + MovementY());

	return true;
}

bool CMouse::ReadBufferedDevice()
{
	if (!m_pDevice)
		return false;

	ClearBufferedData();

	if (FAILED(m_pDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0)))
	{
		if (FAILED(m_pDevice->Acquire()))
			return false;

		ClearBufferedData();

		if (FAILED(m_pDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0)))
			return false;
	}

	return false;
}

bool CMouse::ButtonDown(unsigned char ucButton)
{
	return m_diMouseState.rgbButtons[ucButton] & 0x80 ? true : false;
}

bool CMouse::ButtonPressed(unsigned char ucButton)
{
	return ButtonDown(ucButton) && !(m_diPrevMouseState.rgbButtons[ucButton] & 0x80);
}

bool CMouse::ButtonPressedEx(unsigned char ucButton)
{
	for (DWORD i = 0; i < m_dwBufferElements; ++i)
		if (m_didod[i].dwOfs == (DWORD)(DIMOFS_BUTTON0 + ucButton) && m_didod[i].dwData & 0x80)
			return true;

	return false;
}

bool CMouse::ButtonUp(unsigned char ucButton)
{
	return !ButtonDown(ucButton);
}

bool CMouse::ButtonReleased(unsigned char ucButton)
{
	return ButtonUp(ucButton) && m_diPrevMouseState.rgbButtons[ucButton] & 0x80;
}

bool CMouse::ButtonReleasedEx(unsigned char ucButton)
{
	for (DWORD i = 0; i < m_dwBufferElements; ++i)
		if (m_didod[i].dwOfs == (DWORD)(DIMOFS_BUTTON0 + ucButton) && !(m_didod[i].dwData & 0x80))
			return true;

	return false;
}

int CMouse::CheckBufferedButtons()
{
	int button = -1;

	for (int j = 0; j < GetNumButtons(); ++j)
	{
		if (ButtonPressed(j))
		{
			button = j;
			break;
		}
	}

	return button;
}

int CMouse::CheckBufferedButtonsEx()
{
	int button = -1;

	for (DWORD i = 0; i < m_dwBufferElements; ++i)
	{
		for (int j = 0; j < GetNumButtons(); ++j)
		{
			if (m_didod[i].dwOfs == (DWORD)(DIMOFS_BUTTON0 + j) && m_didod[i].dwData & 0x80)
			{
				button = j;
				break;
			}
		}
	}

	return button;
}

long CMouse::MovementX()
{
	return m_diMouseState.lX;
}

long CMouse::MovementY()
{
	return m_diMouseState.lY;
}

long CMouse::WheelMovement()
{
	return m_diMouseState.lZ;
}